home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HPAVC
/
HPAVC CD-ROM.iso
/
BG_SRC.ZIP
/
BG_GRAF1.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-12-31
|
17KB
|
489 lines
/*
*
* B G _ G R A F 1 . C
* A graphics module for the backgammon playing program BG.C.
* This version 30th January 1993
*
*
+--------------------+--------+ Here is the screen layout.
| | dice |
| | area |
| board +--------+ The dice area must always
| | face | have a 2-1 aspect ratio, and the
| area | area | text area must always have SIDE_ROWS
| +--------+ and SIDE_COLS. The logo area is
| | | a buffer zone. The help area holds
| | text | one line of text.
+--------------------+ area |
| help area | |
+--------------------+--------+ The board area is
further divided into a grid of 14 by 12, which is used as the basis for
drawing the points and the pieces, see BG_GRAF2.C.
*****************************************************************************/
#include "comp.h"
#include <stdlib.h>
#include <stdio.h>
#include <bios.h>
#include <conio.h>
#include <math.h>
#include "bg.h"
/****************************************************************************/
/* Local defines ... */
Disp_Cfg_t Disp_Cfg ; /* How the hardware has come to me */
Screen_Const_t Grafs ; /* How I have divided the screen areas */
/* Here is the dice graphics structure */
static struct {
short Area_Wide ; /* Pixel sizeof entire... */
short Area_High ; /* ...area, inclusive */
short Wide,High ; /* Actual size of a single dice */
short Dot_Wide ; /* Size of a dot... */
short Dot_High ; /* ...on a face */
short Dice1_X,Dice2_X ; /* X position of the two die */
short X,Y ; /* Absoulte screen position of dice area */
short T_Row,T_Col ; /* A row of text below the dice, defined on the
text grid, to show dice as a row of numbers */
} Dice_Gr ;
boolean Force_BW = FALSE ; /* Force a black&white display from command line */
/****************************************************************************/
/**** LOCAL PRIVATE FUNCTIONS ****/
static void Init_Text_Fields (void) ;
static void Init_Dice_Grafs (void) ;
/****************************************************************************/
void Init_Graphics (void)
/*
PURPOSE: To initialise the screen to graphics mode and to set up
the various graphics structures used throughout the
program
*/
{
{
#define CGATEST 0
#define EGATEST 0
#define IBMTEST 0
int G_Driver,G_Mode,G_Error ;
#if CGATEST
G_Driver = CGA ;
G_Mode = CGAHI ;
printf ("\nWARNING: CGATEST:") ; (void)getch () ;
#elif EGATEST
G_Driver = EGA ;
G_Mode = EGAHI ;
printf ("\nWARNING: EGATEST:") ; (void)getch () ;
#elif IBMTEST
G_Driver = IBM8514 ;
G_Mode = 0 ;
printf ("\nWARNING: IBMTEST:") ; (void)getch () ;
#else
G_Driver = DETECT ;
#endif
initgraph (&G_Driver,&G_Mode,"C:\\BORLANDC\\BGI") ;
G_Error = graphresult () ;
if (G_Error != grOk) {
printf ("\nError %s",grapherrormsg(G_Error));
(void)getch () ;
exit (1) ;
} else if (G_Driver == CGA) {
closegraph () ;
printf ("\nERROR: This program requires an EGA or a VGA display.") ;
exit (1) ;
}
Disp_Cfg.Colour = TRUE ;
switch (G_Driver) {
case HERCMONOHI :
case EGAMONO :
Disp_Cfg.Colour = FALSE ;
break ;
case VGA:
setgraphmode (VGAMED) ;
break ;
case IBM8514:
setgraphmode (0) ;
break ;
}
if (Force_BW) {
Disp_Cfg.Colour = FALSE ;
}
}
Get_Display_Config (&Disp_Cfg) ;
Init_Text_Fields () ; /* The other fields made to fit with text */
Grafs.Dice_Area_Y = 1 ;
Grafs.Dice_Area_X = Grafs.Text_X ;
Init_Dice_Grafs () ;
Init_And_Draw_Logo () ;
Grafs.Board_X = 1 ;
Grafs.Board_Y = 1 ;
Grafs.Board_Wide = Disp_Cfg.X_Pixels - Grafs.Text_Wide - (2*Disp_Cfg.Char_Wide) ;
Grafs.Board_High = Disp_Cfg.Y_Pixels - (Disp_Cfg.Char_High*2) - 2 ;
Grafs.Help_Y = Grafs.Board_High ;
Grafs.Grid_Wide = Grafs.Board_Wide / GRID_COLS ;
Grafs.Grid_High = Grafs.Board_High / GRID_ROWS ;
Grafs.Board_Wide = GRID_COLS * Grafs.Grid_Wide ; /* Now they are ... */
Grafs.Board_High = GRID_ROWS * Grafs.Grid_High ; /* ...exact multiples. */
Grafs.Unit_Wide = Grafs.Grid_Wide-4 ;
Grafs.Unit_High = Grafs.Grid_High-4 ;
Get_Grid_Corner (&Grafs.Double_X,&Grafs.Double_Y,BAR_COL,DOUBLE_ROW) ;
}
/****************************************************************************/
static void Init_Text_Fields (void)
/*
PURPOSE: To initialise the text fields so that there is a block of text
to the left-bottom of TEXT_ROWS high and TEXT_COLS wide. We also init
the help text area so that there is a single row of text available.
The positions are based on a character sized matrix over the whole screen
because some compilers and or devices cannot put text at abitrary x-y
positions.
*/
{
Grafs.Text_Wide = SIDE_COLS*Disp_Cfg.Char_Wide ;
Grafs.Text_High = SIDE_ROWS*Disp_Cfg.Char_High ;
Grafs.Text_X = Disp_Cfg.X_Pixels - Grafs.Text_Wide ;
Grafs.Text_Y = Disp_Cfg.Y_Pixels - Grafs.Text_High ;
Grafs.Help_X = 0 ;
Grafs.Help_Y = (Disp_Cfg.Y_Pixels/Disp_Cfg.Char_High) * Disp_Cfg.Char_High ;
Grafs.Help_Wide = Disp_Cfg.X_Pixels - Grafs.Text_Wide ;
Grafs.Help_Cols = Disp_Cfg.Text_Cols - SIDE_COLS ;
}
/****************************************************************************/
void Get_Grid_Corner (short* Grid_X, short* Grid_Y,
short Grid_Col, short Grid_Row)
/*
PURPOSE: To return in Grid_X, Grid_Y the absolute coords of the
top left of the Grid_Row,Grid_Col square.
*/
{
(*Grid_X) = Grafs.Board_X + ((Grid_Col*Grafs.Board_Wide)/GRID_COLS) ;
(*Grid_Y) = Grafs.Board_Y + ((Grid_Row*Grafs.Board_High)/GRID_ROWS) ;
}
/**************************************************************************/
void Get_Grid_Center (short* Grid_X, short* Grid_Y,
short Grid_Col, short Grid_Row)
/*
PURPOSE: To return in Grid_X, Grid_Y the absolute coords of the
middle of the Grid_Row,Grid_Col square.
*/
{
Get_Grid_Corner (Grid_X,Grid_Y,Grid_Col,Grid_Row) ;
(*Grid_X) = (*Grid_X) + (Grafs.Grid_Wide/2) ;
(*Grid_Y) = (*Grid_Y) + (Grafs.Grid_High/2) ;
}
/**************************************************************************/
void Draw_Dice_Pair (Dice_t* Pair, Player_t Player)
/*
PURPOSE: To show the two dice with the two values.
*/
{
Draw_Die (Pair->Values[0],1,Player) ;
Draw_Die (Pair->Values[1],2,Player) ;
}
/**************************************************************************/
/* The following array is initialised to the positions of dots for the
6 values of the dice faces when the face is divided into a 10 by 10 grid */
static short Dot_Pos_Arr [7][6][2] =
{{{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* Value0 has no face */
{{5,5},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* Single dot in centre */
{{2,5},{8,5},{0,0},{0,0},{0,0},{0,0}}, /* Two dots */
{{2,5},{8,5},{5,5},{0,0},{0,0},{0,0}}, /* Three dots */
{{2,2},{8,8},{2,8},{8,2},{0,0},{0,0}}, /* Four dots */
{{2,2},{8,8},{2,8},{8,2},{5,5},{0,0}}, /* Five dots */
{{2,2},{5,2},{8,2},{2,8},{5,8},{8,8}}}; /* Five dots */
/* Later these values will be recalculated to make them the top left
corner of the dots. */
static void Init_Dice_Grafs (void)
/*
PURPOSE: To set up the dice graphic variables.
NOTES : 1) The basic area is derived starting from Text_Wide.
2) The two dice are arranged as a horizontal pair, with
separated one from the other by 2 DICE_MARGINS and
from the edge of the area by a single DICE_MARGIN.
*/
{
#define DICE_MARGIN 4
short y,v,dot ;
Dice_Gr.Area_Wide = Grafs.Text_Wide ;
Dice_Gr.X = Grafs.Text_X ;
Dice_Gr.Wide = (Dice_Gr.Area_Wide - (4*DICE_MARGIN)) / 2 ;
Dice_Gr.High = (Dice_Gr.Wide * Disp_Cfg.Aspect_V) / Disp_Cfg.Aspect_H ;
Dice_Gr.Area_High = Dice_Gr.High +
((2*(DICE_MARGIN*Disp_Cfg.Aspect_V))/Disp_Cfg.Aspect_H) ;
y = Dice_Gr.Area_High + (2*Disp_Cfg.Char_High) ;
Dice_Gr.T_Row = (y / Disp_Cfg.Char_High) - 1 ;
Dice_Gr.Area_High = Dice_Gr.Area_High + (2*Disp_Cfg.Char_High) ;
Dice_Gr.T_Col = Disp_Cfg.Text_Cols - SIDE_COLS ;
Dice_Gr.Dice1_X = Grafs.Dice_Area_X + DICE_MARGIN ;
Dice_Gr.Dice2_X = Grafs.Dice_Area_X + (3*DICE_MARGIN) + Dice_Gr.Wide ;
Dice_Gr.Y = Grafs.Dice_Area_Y +
((DICE_MARGIN*Disp_Cfg.Aspect_V)/Disp_Cfg.Aspect_H) ;
Dice_Gr.Dot_Wide = Dice_Gr.Wide / 5 ;
Dice_Gr.Dot_High = Dice_Gr.High / 5 ;
/* Setup positions for drawing dots */
for (v = 1 ; v <= 6 ; v++) {
for (dot = 0 ; dot < 6 ; dot++) {
Dot_Pos_Arr[v][dot][XI] = (Dot_Pos_Arr[v][dot][XI]*Dice_Gr.Wide)/10 ;
Dot_Pos_Arr[v][dot][XI] = Dot_Pos_Arr[v][dot][XI] -
(Dice_Gr.Dot_Wide/2) ;
Dot_Pos_Arr[v][dot][YI] = (Dot_Pos_Arr[v][dot][YI]*Dice_Gr.High)/10 ;
Dot_Pos_Arr[v][dot][YI] = Dot_Pos_Arr[v][dot][YI] -
(Dice_Gr.Dot_High/2);
}
}
}
/****************************************************************************/
void Draw_Die (short Value, short Dice_Num, Player_t Player)
/*
PURPOSE: To draw a single die of Value. X_Pos is determined by Dice_Num
which should be 1 or 2.
*/
{
short dot,Fill_Color,Dot_Color,X_Pos ;
if ((Value < 1) || (Value > 6)) {
printf ("\nBad value in Draw_Die (%d,%d,%d)",Value,Dice_Num,Player) ;
Error_Exit ("\nBad Value in Draw_Die") ;
}
if (Disp_Cfg.Colour) {
if (Player == BLACK_PLAYER) {
Fill_Color = LIGHTRED ;
Dot_Color = WHITE ;
} else {
Fill_Color = WHITE ;
Dot_Color = RED ;
}
} else {
if (Player == BLACK_PLAYER) {
Fill_Color = BLACK ;
Dot_Color = WHITE ;
} else {
Fill_Color = WHITE ;
Dot_Color = BLACK ;
}
}
if (Dice_Num == 1) {
X_Pos = Dice_Gr.Dice1_X ;
} else {
X_Pos = Dice_Gr.Dice2_X ;
}
Fill_Rect (X_Pos,Dice_Gr.Y,Dice_Gr.Wide,Dice_Gr.High,Fill_Color) ;
Draw_Rect (X_Pos,Dice_Gr.Y,Dice_Gr.Wide,Dice_Gr.High,WHITE) ;
/* draw the dots... */
for (dot = 0 ; dot < Value ; dot++) {
Fill_Rect (X_Pos + Dot_Pos_Arr [Value][dot][XI],
Dice_Gr.Y + Dot_Pos_Arr [Value][dot][YI],
Dice_Gr.Dot_Wide,Dice_Gr.Dot_High,Dot_Color) ;
}
}
/**************************************************************************/
void Clear_Die (short Dice_Num)
/*
PURPOSE: To clear the area of a single die of X_Pos is determined
by Dice_Num which should be 1 or 2.
*/
{
short X_Pos ;
if (Dice_Num == 1) {
X_Pos = Dice_Gr.Dice1_X ;
} else {
X_Pos = Dice_Gr.Dice2_X ;
}
Fill_Rect (X_Pos,Dice_Gr.Y,Dice_Gr.Wide,Dice_Gr.High+1,BLACK) ;
}
/**************************************************************************/
void Draw_Stats (void)
/*
PURPOSE: To draw the current statistics in the statistics box
*/
{
extern Stats_t Statistics[2] ;
extern int Target_Score ;
short p ;
Print_Message (ID_MSG) ;
Print_Message (TOTAL_MSG) ;
Print_Message (DOUBLE_MSG) ;
Print_Message (POINTS_MSG) ;
for (p = BLACK_PLAYER ; p < N_PLAYERS ; p++) {
Side_Number (TOTALN_ROW, (ushort)(p*NUM_WIDE),
Statistics[p].Total,NUM_WIDE,15) ;
Side_Number (DOUBN_ROW, (ushort)(p*NUM_WIDE),
Statistics[p].Doubles,NUM_WIDE,15) ;
Side_Number (POINTSN_ROW, (ushort)(p*NUM_WIDE),
Statistics[p].Games_Won,NUM_WIDE,15) ;
Print_Message (PLAY_TO_MSG) ;
Side_Number (TARGETN_ROW,(ushort)(p*NUM_WIDE),
Target_Score,NUM_WIDE,15) ;
}
}
/**************************************************************************/
void Graf_Number (ushort Row, ushort Col, ushort Number,
ushort F_Size, ushort Color)
/*
PURPOSE: To print the number at the Row,Col on the graphics screen.
*/
{
char Num_Str [16] ;
ushort c ;
/* Blank area for string */
for (c = 0 ; c < F_Size ; c++) {
Graf_Text (Row,Col+c," ",Color) ;
}
(void)itoa (Number,Num_Str,10) ;
Graf_Text (Row,Col,Num_Str,Color) ;
}
/**************************************************************************/
void Side_Number (ushort Row, ushort Col, ushort Number,
ushort F_Size, ushort Color)
/*
PURPOSE: To print the number at the Row,Col of the side text in the
specified field size and color.
*/
{
char Num_Str [16] ;
ushort c ;
/* Blank area for string */
for (c = 0 ; c < F_Size ; c++) {
Side_Text (Row,Col+c," ",Color) ;
}
(void)itoa (Number,Num_Str,10) ;
Side_Text (Row,Col,Num_Str,Color) ;
}
/**************************************************************************/
void Init_And_Draw_Logo (void)
/*
PURPOSE: To draw the largest logo in the center of the space left for
that purpose. The space is what remains after the text and
dice areas have been initialised.
*/
{
short Wide,High ;
/* Initialise the fields telling us the area available */
Grafs.Logo_Y = Dice_Gr.Area_High + 2 ; /* 2 dividing lines */
Grafs.Logo_X = Grafs.Text_X ;
Grafs.Logo_High = Disp_Cfg.Y_Pixels - Dice_Gr.Area_High -
Grafs.Text_High - 4 ; /* 4 dividing lines */
if (Grafs.Logo_High <= 5) {
printf ("\nGrafs.Logo_High too small: %d.",Grafs.Logo_High) ;
Error_Exit ("Logo_High too small") ;
}
Grafs.Logo_Wide = Grafs.Text_Wide ;
if (Grafs.Logo_Wide > ((Grafs.Logo_High*Disp_Cfg.Aspect_H)/Disp_Cfg.Aspect_V)) {
/* Area is wider than high, logo square based on height */
High = Grafs.Logo_High-2 ;
Wide = (High*Disp_Cfg.Aspect_H)/Disp_Cfg.Aspect_V ;
} else {
/* Area is higher than wide, logo square based on width */
Wide = Grafs.Logo_Wide-2 ;
High = (Grafs.Logo_Wide*Disp_Cfg.Aspect_V)/Disp_Cfg.Aspect_H ;
}
/* Now Wide and High should draw a square on the screen */
Grafs.Logo_X = ((Grafs.Logo_Wide - Wide) / 2) + Grafs.Logo_X + 1 ;
Grafs.Logo_Y = ((Grafs.Logo_High - High) / 2) + Grafs.Logo_Y + 1;
Grafs.Logo_Wide = Wide ;
Grafs.Logo_High = High ;
Grafs.Logo_Center = Grafs.Logo_X + (Grafs.Logo_Wide/2) ;
}
/**************************************************************************/
void Clear_Logo_Area (void)
/*
PURPOSE: To clear the logo area to black.
*/
{
Fill_Rect (Grafs.Logo_X,Grafs.Logo_Y,
Grafs.Logo_Wide,Grafs.Logo_High,BLACK) ;
}
/**************************************************************************/
boolean Even (short Number)
{
if (((Number/2)*2) == Number) {
return (TRUE) ;
} else {
return (FALSE) ;
}
}
/**************************************************************************/
void Show_Dice_List (Dice_t* Dice)
/*
PURPOSE: To list the dice (0..4) as some digits below the drawing of the
dice.
*/
{
short i ;
for (i = 0 ; i < SIDE_COLS ; i++ ) {
Graf_Text (Dice_Gr.T_Row, Dice_Gr.T_Col+i,"-",WHITE) ;
}
for (i = 0 ; i < Dice->N_Vals ; i++) {
Graf_Number (Dice_Gr.T_Row,Dice_Gr.T_Col+(2*i)+2,
Dice->Values[i],1,WHITE) ;
}
}
/***************************************************************************/